require 'open-uri'

class Backup < ActiveRecord::Base

  attr_accessor :data_source, :output_path

  belongs_to :user

  validates_presence_of :name, :user_id
  # validates_associated :user
  validates_uniqueness_of :name
  validates_existance_of :user

  before_validation :set_type_column, :set_default_name

  def meta_as_hash
    if meta then YAML::load( meta.to_s ) else {} end
  end
  def set_meta_attribute name, value
    self.meta = meta_as_hash.merge({ name => value }).to_yaml
  end

  def data_source
    @data_source ||= LocalDataSource.new Backup.path
  end
  def write path, data
    data_source.write path, data
  end

  # returns the HTML result of a simple HTTP GET request
  def get url
    open(url).read
  end

  # i sortof want this to be #call instead, so lambdas can be used
  def run
    raise "No backup logic implemented for #{ self.class }"
  end

  def output_path
    @outpath || "#{id}-#{pretty_class_name_for_output_path}"
  end

  def meta_attributes
    self.class.meta_attributes
  end

  class << self

    attr_accessor :path, :plugins, :meta_attributes

    def path
      @path ||= 'reserve-chute-backups'
    end

    def meta_attributes
      @meta_attributes ||= []
    end
    
    def attr_meta *attrs
      attrs.each do |name|
        meta_attributes << name
        define_method name do
          meta_as_hash[name]
        end
        define_method "#{name}=" do |value|
          set_meta_attribute name, value
        end
      end
    end

  end

  def self.plugins
    ReserveChute.plugins ||= self.subclasses
  end

protected

  # type column doesn't expect to be nil, so we set it, if it isn't set
  def set_type_column
    self.type = self.class.to_s unless type
  end

  # set a default :name for derived Backup objects
  def set_default_name
    self.name = type unless name
  end

  # DeliciousBackupsFooBar -> delicious_foo_bar
  def pretty_class_name_for_output_path
    self.class.to_s.underscore.gsub('backup','').gsub(/_{2,}/,'_').sub(/^_/,'').sub(/_$/,'')
  end

end
